package com.cksys.achievement.config;

import com.cksys.achievement.config.login.qq.*;
import com.cksys.achievement.service.impl.CustomUserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.sql.DataSource;

/**
 * @ClassName: WebSecurityConfig
 * @author: zyx
 * @E-mail: 1377631190@qq.com
 * @DATE: 2020/3/8 20:21
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${qq.client.id}")
    private String qqClientId;
    @Value("${qq.client.secret}")
    private String qqClientSecret;
    @Value("${qq.redirect}")
    private String qqRedirectUri;

    @Autowired
    QQBindingManager qqBindingManager;

    @Autowired
    private CustomUserDetailsServiceImpl customUserDetailsServiceImpl;

    @Autowired
    private QQAuthenticationManager qqAuthenticationManager;

    @Autowired
    BCryptPasswordEncoder encoder;

    @Autowired
    AjaxAuthFailureHandler authFailureHandler;

    @Autowired
    AjaxAuthSuccessHandler successHandler;

    @Autowired
    ValidateCodeFilter validateCodeFilter;

    @Autowired
    MyLogoutSuccessHandler logoutSuccessHandler;

    @Autowired
    private DataSource dataSource;

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl persistentTokenRepository = new JdbcTokenRepositoryImpl();
        persistentTokenRepository.setDataSource(dataSource);
        return persistentTokenRepository;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserDetailsServiceImpl)
                .passwordEncoder(encoder);
    }

    private QQAuthenticationFilter qqAuthenticationFilter() {
        QQAuthenticationFilter qqAuthenticationFilter = new QQAuthenticationFilter(
                new AntPathRequestMatcher("/qqlogin", "GET"), qqClientId, qqClientSecret, qqRedirectUri);
        qqAuthenticationFilter.setAuthenticationManager(qqAuthenticationManager);
        qqAuthenticationFilter.setAuthenticationFailureHandler(authFailureHandler);
        qqAuthenticationFilter.setAuthenticationSuccessHandler(new QQAuthenticationSuccessToIndexHandler("/"));
        return qqAuthenticationFilter;
    }

    private QQBindingFilter qqBindingFilter() {
        QQBindingFilter qqBindingFilter = new QQBindingFilter(new AntPathRequestMatcher("/qqbind", "POST"));
        qqBindingFilter.setAuthenticationManager(qqBindingManager);
        qqBindingFilter.setAuthenticationFailureHandler(new QQAuthenticationFailureHandler());
        qqBindingFilter.setAuthenticationSuccessHandler(new QQAuthenticationSuccessHandler());
        return qqBindingFilter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(qqAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(qqBindingFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
                .authorizeRequests()
                // 如果有允许匿名的url，填在下面
                .antMatchers("/", "/download/demo", "/user/register", "/binding/**", "/qqbind",
                        "/test", "/verifycode/get", "/admin", "/email/activation", "/forget", "/email/get",
                        "/user/findPassword", "/result/list", "/result/top/get", "/result/user/top")
                .permitAll()
                .anyRequest().authenticated()
                .and()
                // 设置登陆页
                .formLogin()
                    .loginPage("/")
                    .loginProcessingUrl("/login")
                    .usernameParameter("username")
                    .passwordParameter("password")
                    .successHandler(successHandler)
                    .failureHandler(authFailureHandler)
                    .permitAll()
                .and()
                .rememberMe()
                    .tokenRepository(persistentTokenRepository())
                    .tokenValiditySeconds(3600)
                    .userDetailsService(userDetailsService())
                .and()
                .logout()
                    .logoutUrl("/logout")
                    .logoutSuccessHandler(logoutSuccessHandler)
                    .deleteCookies("JSESSIONID")
                .permitAll();

          // 关闭CSRF跨域
//        http.csrf().disable().headers().frameOptions().disable();

        http.headers().frameOptions().disable();
    }

    @Override
    public void configure(WebSecurity web) {
        // 设置拦截忽略文件夹，可以对静态资源放行
        web.ignoring().antMatchers("/css/**", "/js/**", "/fonts/**", "/images/**", "/tags/**");
    }

}
